<?php

class Html_Element
{

    /**
     * other options like html attributes
     */
    protected $_attrib = array();

    /**
     * meta data options
     * @var array
     */
    protected $_meta = array();

    /**
     * childrens
     * @var array
     */
    protected $_children = array();

    /**
     * @param string $type
     * @param string $name
     * @param array $options
     * @return Html_Element_Group
     */
    public function addChild($type, $name = null, $options = array())
    {
        if (null == $name)
        {
            $name = 'id_' . str_replace('@', '_', $type);
        }

        $this -> _children[$name] = Nuo::getResource($type, 'htmlElement') -> setName($name) -> setOptions($options);

        return $this;
    }

    /**
     * @param string $name
     * @return Html_Element
     */
    public function getChild($name)
    {
        return isset($this -> _children[$name]) ? $this -> _children[$name] : null;
    }

    /**
     * @param string $name
     * @return Html_Element_Group
     */
    public function removeChild($name)
    {
        if (isset($this -> _children[$name]))
        {
            unset($this -> _children[$name]);
        }
        return $this;
    }

    /**
     * @param array
     * @return Html_Element
     */
    public function setChildren($values)
    {
        foreach ($values as $value)
        {
            $this -> _children[$value['name']] = Nuo::getResource($value['type'], 'element') -> setName($value['name']) -> setOptions(isset($value['options']) ? $value['options'] : array());
        }
        return $this;

    }

    /**
     * get array of element
     * @return array
     */
    public function getChildren()
    {
        return $this -> _children;
    }

    /**
     * check element exists
     * @return bool
     */
    public function hasChild($name)
    {
        return isset($this -> _children[$name]);
    }

    /**
     * @return bool
     */
    public function hasChildren()
    {
        return empty($this -> _children);
    }

    /**
     * @param string $name
     * @param string $value
     * @return Html_Element
     */
    public function setMeta($name, $value = null)
    {
        if (!is_string($name) && is_array($name))
        {
            foreach ($name as $k => $v)
            {
                $this -> _meta[$k] = $v;
            }
        }
        else
        if ($name)
        {
            $this -> _meta[$name] = $value;
        }
        return $this;
    }

    /**
     * @param string $name
     * @param string $default
     * @return string
     */
    public function getMeta($name = null, $default = null)
    {
        if (null == $name)
        {
            return $this -> _meta;
        }
        return isset($this -> _meta[$name]) ? $this -> _meta[$name] : $default;
    }

    /**
     * clear all meta options
     * @return Html_Elment
     */
    public function clearMeta()
    {
        $this -> _meta = array();
        return $this;
    }

    /**
     * remove meta config
     */
    public function removeMeta($name)
    {
        if (isset($this -> _meta[$name]))
        {
            unset($this -> _meta[$name]);
        }
        return $this;
    }

    /**
     * @param string $name
     * @param string $value
     * @return Html_Element
     */
    public function setAttrib($name, $value = null)
    {
        if (!is_string($name) && is_array($name))
        {
            foreach ($name as $k => $v)
            {
                $this -> _attrib[$k] = $v;
            }
        }
        else
        if ($name)
        {
            $this -> _attrib[$name] = $value;
        }
        return $this;
    }

    /**
     * @param string $name
     * @param string $value
     * @return string
     */
    public function getAttrib($name = null, $default = null)
    {
        if (null == $name)
        {
            return $this -> _attrib;
        }
        return isset($this -> _attrib[$name]) ? $this -> _attrib[$name] : $default;
    }

    /**
     * clear all attribute
     * @return Html_Element
     */
    public function clearAttrib()
    {
        $this -> _attrib = array();
        return $this;
    }

    /**
     * remove attribute
     * @return Html_Element
     */
    public function removeAttrib($name)
    {
        if (isset($this -> _attrib[$name]))
        {
            unset($this -> _attrib[$name]);
        }
        return $this;
    }

    /**
     * base method, need to override from super class
     */
    protected function _init()
    {

    }

    /**
     * @param array $value
     * @return Html_Element
     */
    public function setErrors($value)
    {
        $this -> _errors = $value;
        return $this;
    }

    /**
     * @return array
     */
    public function getErrors()
    {
        return $this -> _errors;
    }

    /**
     * clear all errors
     * @return Html_Element
     */
    public function clearError()
    {
        $this -> _errors = array();
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function addError($value)
    {
        $this -> _errors[] = $value;
        return $this;
    }

    public function setName($name)
    {
        if ($name)
        {
            $this -> _meta['name'] = $name;
        }

        return $this;
    }

    public function getName()
    {
        return $this -> _meta['name'];
    }

    public function setValue($value)
    {
        $this -> _meta['value'] = $value;
        return $this;
    }

    public function getValue()
    {
        return $this -> _meta['value'];
    }

    public function clearValue()
    {
        $this -> _meta['value'] = null;
        return $this;
    }

    public function removeValue()
    {
        $this -> _meta['value'] = null;
    }

    public function setOptions($options)
    {
        foreach ($options as $key => $value)
        {
            if (method_exists($this, $method = 'set' . ucfirst($key)))
            {
                $this -> {$method}($value);
            }
            else
            {
                $this -> _attrib[$key] = $value;
            }
        }
        return $this;
    }

    public function render()
    {
        $this -> beforeRender();
        return (string)Nuo::getResource($this -> getRender(), 'htmlRender') -> render($this);
    }

    public function __toString()
    {
        return $this -> render();
    }

    /**
     * constructor
     * @return void
     */
    public function __construct()
    {
        $this -> _init();
    }

    public function beforeRender()
    {

    }

    public function flatAttrib()
    {
        $xhtml = array();
        foreach ($this->_attrib as $key => $value)
        {
            $xhtml[] = $key . '="' . $value . '"';
        }
        return implode(' ', $xhtml);
    }

    /**
     * alias call
     * @return string
     */
    public function getDesc()
    {
        return isset($this -> _meta['desc']) ? $this -> _meta['desc'] : '';
    }

    /**
     * alias call
     * @return string
     */
    public function getLabel()
    {
        return isset($this -> _meta['label']) ? $this -> _meta['label'] : '';
    }

    /**
     * alias call
     * @return string
     */
    public function getTitle()
    {
        return isset($this -> _meta['title']) ? $this -> _meta['title'] : '';
    }

    /**
     * alias call
     * @return string
     */
    public function getNoLabel()
    {
        return isset($this -> _meta['noLabel']) ? $this -> _meta['noLabel'] : 0;
    }

    /**
     * alias call
     * @return string
     */
    public function getNoTitle()
    {
        return isset($this -> _meta['noTitle']) ? $this -> _meta['noTitle'] : 0;
    }

    /**
     * alias call
     * @return string
     */
    public function getNoDesc()
    {
        return isset($this -> _meta['noDesc']) ? $this -> _meta['noDesc'] : 0;
    }

    /**
     * alias call
     * @return string
     */
    public function getRender()
    {
        return isset($this -> _meta['render']) ? $this -> _meta['render'] : '@input';
    }

    /**
     * @return string
     */
    public function getTagName()
    {
        return isset($this -> _meta['tagName']) ? $this -> _meta['tagName'] : 'span';
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setTagName($value)
    {
        $this -> _meta[$name] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setDesc($value)
    {
        $this -> _meta['desc'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setLabel($value)
    {
        $this -> _meta['label'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setNoLabel($value)
    {
        $this -> _meta['noLabel'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setNoTitle($value)
    {
        $this -> _meta['noTitle'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setNoDesc($value)
    {
        $this -> _meta['noDesc'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setTag($value)
    {
        $this -> _meta['tag'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setRender($value)
    {
        $this -> _meta['render'] = $value;
        return $this;
    }

    /**
     * @param string $value
     * @return Html_Element
     */
    public function setTitle($value)
    {
        $this -> _meta['title'] = $value;
        return $this;
    }

    /**
     * @param bool $value
     * @return Html_Element
     */
    public function setRequired($value)
    {
        $this -> _meta['required'] = (bool)$value;
        return $this;
    }

    /**
     * @return bool
     */
    public function getRequired()
    {
        return isset($this -> _meta['required']) ? $this -> _meta['required'] : false;
    }

    /**
     * @param array $values
     * @return array
     */
    public function setValidators($values)
    {
        $this -> _meta['validator'] = $values;
        return $this;
    }

    /**
     * alias call
     * @return array
     */
    public function getValidators()
    {
        return isset($this -> _meta['validator']) ? $this -> _meta['validator'] : array();
    }

    /**
     * @param array $values
     * @return Html_Element
     */
    public function setFilters($values)
    {
        $this -> _meta['filter'] = $values;
        return $this;
    }

    /**
     * @return array
     */
    public function getFilters()
    {
        return isset($this -> _meta['filter']) ? $this -> _meta['filter'] : array();
    }

    /**
     * magic getter method.
     * @param string $name
     * @return null
     */
    public function __get($name)
    {
        if (isset($this -> _children[$name]))
        {

            return $this -> _children[$name];
        }

        if (isset($this -> _meta[$name]))
        {
            return $this -> _meta[$name];
        }

        if (isset($this -> _attrib[$name]))
        {
            return $this -> _attrib[$name];
        }

        if (method_exists($this, $method = 'get' . ucfirst($name)))
        {
            return $this -> {$method}();
        }
        return null;
    }

    /**
     * @return array
     */
    public function getValues()
    {
        $data = array();
        foreach ($this->_children as $name => $element)
        {
            $data[$name] = $element -> getValue();
        }
        return $data;
    }

    /**
     * set value
     * @return Html_Element_Group
     */
    public function setValues($values)
    {

        foreach ($this->_children as $name => $element)
        {
            if ($element  instanceof Html_Group)
            {
                $element -> setValues($values);
            }
            else
            {
                $element -> setValue(isset($values[$name]) ? $values[$name] : null);
            }
        }
        return $this;
    }

    /**
     * check is valid;
     * @return bool
     */
    protected function _isValid($value)
    {
        $this -> setValue($value);
        return 1;
    }

    /**
     * check is valid data
     * @param array $values
     * @return bool
     *
     */
    public function isValid($values)
    {

        $flag = true;
        foreach ($this->_children as $name => $element)
        {
            if ($element instanceof Html_Group)
            {
                if (!$element -> isValid($values))
                {
                    $flag = false;
                }
            }
            else
            {
                if (!$element -> _isValid(isset($values[$name]) ? $values[$name] : null))
                {
                    $flag = false;
                }
            }
        }
        return $flag;
    }

}
